home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 25
/
Cream of the Crop 25.iso
/
bbs
/
doorinfo.zip
/
ZMRECV.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-14
|
20KB
|
950 lines
/*
**************************************************************************
**
** Doors program to send files via zmodem
**
** Compile instructions for MSC 5.1 and 6.0
** Note - structs.h hsz.h and bbscfg.h are required.
** these files, and lmtca.obj, are available in doorinfo.zip
**
** cl /c /AL /Gs zmrecv.c
** link /st:4096 zmrecv lmtca fsubs;
**************************************************************************
*/
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "dos.h"
#include <time.h>
#include "structs.h"
#include "hsz.h"
#include "bbscfg.h"
#include "crctab.c"
#include "fossil.h"
#include "c:\mt\tcb.h"
void sendzrinit(void);
void sendzskip(void);
void sendzrpos(void);
void sendzack(void);
void sendznak(void);
void sendzfin(void);
void sendhexhdr(char *buf, int count);
int check_timer(time_t t);
void bsend(char *str);
int endtask(char *);
void clear_queue(int q);
unsigned int calccrc(char *buf, int len);
unsigned long calccrc32(char *buf, int len);
int getheader(void);
int getdata(void);
int check_crc(char *buf, int cnt);
typedef struct acct_rec acctp[];
typedef struct user_rec userp[];
acctp far *acct;
userp far *user; /* pointer to an array of user_rec structures */
#define MY_buf_size 10*1024
char MY_buf[MY_buf_size];
unsigned int calccrc();
unsigned long int calccrc32();
time_t t;
char outbuf[40];
int zdle_hit;
char buffer[1100];
char hdrbuf[2200];
char holdbuf[1200];
int holdidx, holdcnt;
char path[60];
unsigned long filepos;
int crc32 = 0; /* use 16 or 32 bit crc */
int recvmode; /* used to determine how much of header
* received */
int hdrincnt; /* must receive 13 bytes */
/* type, 8 bytes of flags, 4 bytes of crc, in ascii hex */
struct msg1
{ /* used for text in/out */
int m1typ;
int m1num; /* line number */
char m1text[1000];
} *m1;
struct msg3
{ /* the initial message with line num and
* queue nums */
int m3typ; /* must be 7 */
int m3line;
int m3inq;
int m3outq;
void far *acctptr;
void far *userptr;
int maxline;
struct cfg_rec far *cfgptr; /* pointer to BBSCFG record */
} *m3;
int who;
int inq, outq;
FILE *fp;
int single_file_mode = 0;
main(int argc, char *argv[])
{
int file_status;
int k, n;
int n1;
unsigned long lj;
int errorcount;
fp = NULL;
m1 = (struct msg1 *) buffer;
m3 = (struct msg3 *) buffer;
/*
** wait for the initialization event from FALKEN.
** it will be event type 7.
** If for some reason we get an event type 8, we must terminate.
*/
time(&t);
m3->m3typ = 0;
while (m3->m3typ != 7)
{
if (testmsg(1))
{
recvmsg(1, buffer, 1000);
if (m3->m3typ == 8)
endtask("[init] abort message received");
}
if (check_timer(t) > 20)
endtask("timeout waiting for init event");
relinq();
}
acct = m3->acctptr;
user = m3->userptr;
/*
** get the input and output queue numbers we have been assigned,
** and which line this user is logged on to.
*/
inq = m3->m3inq;
outq = m3->m3outq;
who = m3->m3line;
/*
** Set line up for 8 bits, no parity, no matter what the original
** settings are for!
*/
holdidx = holdcnt = 0;
(*user)[who].u_timeroff = 1; /* turn off timer during upload */
/*
** Now the main loop -
*/
setpri(2);
if (argc > 1)
{
strcpy(path, argv[1]);
if (path[0] == '-' && path[1] == 'p')
{
if (path[2])
{
strcpy(path, &argv[1][2]); /* skip the -p */
}
else
{
if (argc > 2)
{
strcpy(path, argv[2]);
}
else
{
path[0] = '\0';
}
}
}
else
{
single_file_mode = 1;
}
clear_queue(inq);
}
else
{
/*
** wait for the text message with filenames
*/
time(&t); /* get timer base value */
for (;;)
{
if (testmsg(inq))
{
recvmsg(inq, buffer, 1000);
if (m1->m1typ == 8)
endtask("[path] abort message received");
else if (m1->m1typ == 1)
{
if (strncmp(m1->m1text, "path=", 5) == 0)
{
strcpy(path, m1->m1text + 5);
break;
}
}
}
if (check_timer(t) > 20)
endtask("timeout waiting for path= message");
delay(1);
}
}
m1->m1typ = 8; /* get control of the line */
send_md_msg(outq, buffer, 2);
delay(1);
bsend("Zmodem Batch file upload activated.\r\n");
bsend("Start your Zmodem transfer now....\r\n");
/*
** Now we have to establish the zmodem dialogue. We are the receiver,
** so we have to send ZRINIT packets to the receiver telling him we
** are ready to go!
** Meantime, the sender is sending ZRQINIT packets.
**
*/
holdcnt = holdidx = 0;
for (;;) /* loop forever, waiting for zfin */
{
n = 0; /* ZSINIT or ZFILE not received yet */
errorcount = 0; /* how many ZRQINIT packets have we sent ? */
sendzrinit(); /* send the first zrinit packet */
file_status = 0; /* waiting for zsinit */
while (n == 0)
{
if (k = getheader())/* see if we got a header in */
{
switch (k)
{
case 1: /* hex packet received */
case 4: /* binary-16 */
case 5: /* binary 32 */
switch (hdrbuf[0])
{
case ZRQINIT:
sendzrinit();
break;
case ZSINIT:
/*
** Only controls possible are for escaping control characters, and
** since we are sending only HEX headers, we don;t need to do that.
** So we just ignore any control bites set in the flags
*/
file_status = 1; /* waiting for file info */
filepos = 0L;
sendzack();
break;
case ZFIN:
sendzfin();
delay(1);
endtask("ZFIN received");
break;
case ZABORT:
sendzfin();
delay(1);
endtask("ZABORT received");
break;
case ZFERR:
sendzfin();
delay(1);
endtask("ZFERR received");
break;
case ZFILE:
/*
** A word of warning -
** We do no conversion, compression, or file management.
** We assume that if a file exists, the user is completing an
** aborted download
**
** Call getdata() which will return the entire data buffer received,
** including the crc bytes. All escape encoding will have been removed,
** and it contains pure binary data - in this case, the file name to
** receive.
*/
n1 = getdata();
if (n1 == 203)
{
sendzrinit();
break;
}
if (check_crc(hdrbuf, hdrincnt - (crc32 ? 4 : 2)) == 1)
{
sendznak();
break;
}
/*
** Data is good, and it is the ZCRCW packet we were expecting.
** See if the file exists, and if so, set filepos to the end of file.
** If we received the file name on the command line, just use it.
**
** If we already got the one file we were expecting,
** then skip this file.
*/
if (single_file_mode == 2)
{
sendzskip();
break;
}
strcpy(buffer, path);
if (!single_file_mode)
{
strcat(buffer, hdrbuf);
}
fp = fopen(buffer, "ab");
if (fp == NULL)
{
sendzskip(); /* cannot open file! */
break;
}
else
{
setvbuf(fp, MY_buf, _IOFBF, MY_buf_size);
if (fseek(fp, 0L, SEEK_END) != 0) /* go to end of file */
fseek(fp, 0L, SEEK_SET); /* if err, goto start */
filepos = ftell(fp);
sendzrpos(); /* ack with offset */
file_status = 2;
if (single_file_mode)
single_file_mode = 2;
}
break;
case ZDATA: /* a data packet */
memcpy((void *) &lj, &hdrbuf[1], 4);
if (check_crc(hdrbuf, hdrincnt - (crc32 ? 4 : 2)) == 1)
{
sendznak();
break;
}
else if (lj != filepos)
{
sendzrpos();
break;
}
else
{
getmoredata:
n1 = getdata();
if (n1 == 203)
{
sendzrpos();
}
else
{
if (check_crc(hdrbuf, hdrincnt - (crc32 ? 4 : 2)) == 1)
{
sendzrpos();
break;
}
/*
** got good data, so we will append to the file.
*/
if (fp != NULL)
{
fwrite(hdrbuf, 1, hdrincnt - (crc32 ? 5 : 3), fp);
filepos = ftell(fp);
}
switch (n1)
{
case ZCRCW:
sendzack();
break;
case ZCRCE:
sendzrpos();
break;
case ZCRCG:
goto getmoredata;
break;
case ZCRCQ:
sendzack();
goto getmoredata;
break;
}
}
}
break;
case ZEOF: /* end of file */
if (check_crc(hdrbuf, hdrincnt - (crc32 ? 4 : 2)) == 1)
{
sendznak();
break;
}
memcpy((void *) &lj, &hdrbuf[1], 4);
if (lj == filepos) /* this is real eof */
{
(*acct)[who].uploads++;
(*acct)[who].upload_k += (filepos + 1023L) / 1024L;
if (fp != NULL)
fclose(fp);
fp = NULL;
filepos = 0L;
n = 1; /* send a zrinit */
} /* if not real end of file, ignore
* header */
} /* end inner switch (hdrbuf[0]) */
break;
case 203: /* timeout */
if (++errorcount > 20)
endtask("errorcount > 20"); /* waited too long for
* zrinit */
if (file_status == 2)
{
sendzrpos();
}
else
{
sendzrinit();
}
break;
}
} /* end if getheader */
} /* end while n == 0 */
} /* end for (;;) */
}
void sendzrinit()
{
int j;
char buf[20];
buf[0] = ZRINIT; /* type */
for (j = 1; j < 5; j++)
buf[j] = 0; /* set flags to 0 */
buf[1 + ZF0] = CANFDX | CANOVIO | CANBRK | CANFC32;
buf[1 + ZP1] = 2; /* 0x400 = 1024 byte input buffer */
buf[1 + ZP1] = 0; /* 0x400 = 1024 byte input buffer */
sendhexhdr(buf, 5);
}
void sendzskip()
{
int j;
char buf[20];
buf[0] = ZSKIP; /* type */
for (j = 1; j < 5; j++)
buf[j] = 0; /* set flags to 0 */
sendhexhdr(buf, 5);
}
void sendzrpos()
{
unsigned char buf[20];
buf[0] = ZRPOS; /* type */
memcpy(&buf[1], (void *) &filepos, 4);
sendhexhdr(buf, 5);
}
void sendzack()
{
unsigned char buf[20];
buf[0] = ZACK; /* type */
memcpy(&buf[1], (void *) &filepos, 4);
sendhexhdr(buf, 5);
}
void sendznak()
{
unsigned char buf[20];
buf[0] = ZNAK; /* type */
memcpy(&buf[1], (void *) &filepos, 4);
sendhexhdr(buf, 5);
}
/*
** Utility routines follow
**
** These routines call Multidos interface routines which are available
** with the FALKEN Doors development kit.
**
** See the file MDOS.TXT for a description of the interface routines.
*/
void sendzfin()
{
int j;
char buf[8];
buf[0] = ZFIN; /* type */
for (j = 1; j < 5; j++)
buf[j] = 0; /* set flags to 0 */
sendhexhdr(buf, 5);
}
void sendhexhdr(buf, count)
char *buf;
int count;
{
int j, k;
unsigned int c;
char w[6];
j = k = 0;
c = calccrc(buf, count); /* calccrc returns new buffer length */
buf[count++] = 0xff & (c >> 8);
buf[count++] = 0xff & c;
j = 0;
outbuf[j++] = ZPAD;
outbuf[j++] = ZPAD;
outbuf[j++] = ZDLE;
outbuf[j++] = 'B'; /* send hex header! */
for (k = 0; k < count; k++)
{
sprintf(w, "%2.2x", (int) (0xff & buf[k]));
outbuf[j++] = w[0];
outbuf[j++] = w[1];
}
outbuf[j++] = '\r';
outbuf[j++] = '\n';
outbuf[j++] = 17; /* x-on */
f_send(who, outbuf, j);
}
int check_timer(t)
time_t t;
{
time_t cur_time;
time(&cur_time);
return (int) (cur_time - t);
}
/*
** Send a null terminated string to FALKEN, to be transmitted to
** a particular line;
*/
void bsend(str)
char *str;
{
f_send(who, str, strlen(str));
}
/*
** wait for a message on the input queue named.
** if no message, relinquish our time slice.
** after all, no need to just loop here when other tasks
** can use the processor.
*/
/*
** This program gracefully exits by
** sending the 'task has terminated' message to FALKEN,
** then terminating.
*/
int endtask(char *msg)
{
char b[120];
/*
** Put line parameters back the way they were
*/
sprintf(b, "ZMRECV : %s", msg);
bbslog(b);
if (fp != NULL)
fclose(fp);
(*user)[who].u_timeroff = 0; /* turn off back on */
exit(0);
}
void clear_queue(q)
int q;
{
while (testmsg(q) > 0)
recvmsg(q, buffer, 1024);
}
unsigned int calccrc(buf, len)
char *buf;
int len;
{
unsigned int c;
c = 0;
while (len--)
c = updcrc((0xff & *buf++), c);
c = updcrc(0, c);
c = updcrc(0, c);
return c; /* returns length of buffer, counting crc */
}
unsigned long calccrc32(buf, len)
char *buf;
int len;
{
unsigned long int c;
c = 0xffffffffL;
while (len--)
{
c = UPDC32((0xff & *buf++), c);
}
c = ~c;
return c; /* returns length of buffer, counting crc */
}
getheader()
{
int j, k, m, n;
int cancount;
int bytes_expected;
n = 0;
cancount = 0;
recvmode = 0;
hdrincnt = 0;
for (;;)
{
time(&t); /* wait 20 seconds to receive a header */
while (holdcnt == holdidx)
{
holdidx = 0;
if ((holdcnt = f_recv(who, holdbuf, 1024)) == 0) /* nothing in */
{
if (check_timer(t) > 5)
{
return 203;
}
if (testmsg(inq))
{
recvmsg(inq, buffer, 200);
if (m1->m1typ == 8)
endtask("[getheader] abort message received");
}
relinq();
}
}
time(&t);
while (holdcnt > holdidx) /* got some data waiting */
{
k = holdbuf[holdidx++];
if (k == ZDLE)
{
if (++cancount >= 4)
endtask("[getheader] CAN received.");
}
else
cancount = 0;
switch (recvmode)
{
case 0: /* waiting for zpad */
if (k == ZPAD)
{
recvmode = 1; /* got header, looking for ZDLE */
/* not gonna get zdle, get B */
}
/*
** Got zpad. If next byte not zpad or zdle, start looking for zpad again
** if zpad, continue looking for zdle.
** if zdle, look for header type
*/
break;
case 1: /* got zpad, looking for zdle */
if (k == ZPAD)
break; /* ignore duplicate zpad */
else if (k == ZDLE)
{
recvmode = 2;
hdrincnt = 0;
}
/*
** we must get the 'B' next if this is a ZDLE
** we may get the 'B' without a ZDLE. This is OK, we just start
** accumulating the header
*/
else if (k == 'B')
{
recvmode = 3; /* hex header */
crc32 = 0;
}
else
{
recvmode = 0; /* not one of these - error */
}
break;
case 2: /* got zdle - look for header type. */
if (k == 'B')
{
recvmode = 3; /* hex header */
crc32 = 0;
}
else if (k == 'A') /* 16 bit CRC binary header */
{
recvmode = 4;
crc32 = 0;
bytes_expected = 7;
}
else if (k == 'C') /* 32 bit CRC binary header */
{
recvmode = 5;
crc32 = 1;
bytes_expected = 9;
}
else
{
recvmode = 0; /* wait for pad */
holdidx--; /* reprocess this char */
}
break;
/*
** we are now receiving the data packet from the receiver.
** if it is a hex header, and will be exactly 17 bytes long.
** Type(2) plus 4 flags(8) plus 2 CRC bytes(4) plus cr/lf/xon = 17
** hex encoding, of course
**
** if we get a bad character in, go back to waiting for ZPAD
*/
case 3: /* now assemble hex packet */
if ((k != 17) && (k != 19))
hdrbuf[hdrincnt++] = k;
if ((hdrincnt > 13) && ((0x7f & k) == 10)) /* look for LF */
{
for (j = k = 0; j < 7; j++)
{
n = hdrbuf[k++];
n = tolower(n);
if (n <= '9')
n -= '0';
else
n = (n - 'a') + 10;
m = hdrbuf[k++];
m = tolower(m);
if (m <= '9')
m -= '0';
else
m = (m - 'a') + 10;
hdrbuf[j] = n * 16 + m;
}
recvmode = 0;
return 1; /* show we got a header */
}
break;
case 4: /* binary header */
case 5: /* crc-32 header */
if ((k == 17) || (k == 19))
break; /* ignore these chars */
if (zdle_hit)
{
switch (k)
{
case 'l':
hdrbuf[hdrincnt++] = 0x7f;
break;
case 'm':
hdrbuf[hdrincnt++] = 0xff;
break;
case ZDLEE:
hdrbuf[hdrincnt++] = ZDLE;
break;
default:
hdrbuf[hdrincnt++] = k ^ 0x40;
break;
}
zdle_hit = 0;
}
else /* zdle_hit == 0 */
{
if (k == ZDLE)
zdle_hit = 1;
else
hdrbuf[hdrincnt++] = k;
}
if (hdrincnt == bytes_expected)
{
return recvmode; /* 4 or 5 = bin header */
}
break;
} /* end switch */
} /* end while holdcnt != holdidx */
} /* end for ever */
/*
** We will NEVER get here.
** All returns are from within the FOR(;;) statement
*/
}
/*
** Getdata is called after receiving a ZSINIT, ZFILE, or ZDATA packet.
** We will set a long timer - like 20 seconds.
** We will accumulate data until we find one of :
** ZCRCG, ZCRCW, ZCRCE, ZCRCQ, and return it as the type.
*/
getdata()
{
int k;
int rcrc;
int cancount;
int rtrn;
rcrc = 0; /* will be set to non-zero when getting crc */
cancount = 0;
hdrincnt = 0; /* will be input char count */
zdle_hit = 0;
for (;;)
{
time(&t); /* wait 20 seconds to receive a header */
while (holdcnt == holdidx)
{
holdidx = 0;
if ((holdcnt = f_recv(who, holdbuf, 1024)) == 0) /* nothing in */
{
if (check_timer(t) > 5)
return 203;
if (testmsg(inq))
{
recvmsg(inq, buffer, 200);
if (m1->m1typ == 8)
endtask("[getdata] abort message received");
}
relinq();
}
}
time(&t);
while (holdcnt != holdidx)
{
if (hdrincnt > 2180)
return 203; /* too big! return general timeout error */
k = holdbuf[holdidx++];
/* if over 1040 bytes in receive buffer, error. return and nak */
if ((k == 17) || (k == 19))
continue; /* ignore these chars */
if (k == ZDLE)
{
if (++cancount > 4)
endtask("[getdata] CAN received");
}
else
cancount = 0;
if (zdle_hit)
{
switch (k)
{
case 'l':
hdrbuf[hdrincnt++] = 0x7f;
break;
case 'm':
hdrbuf[hdrincnt++] = 0xff;
break;
case ZDLEE:
hdrbuf[hdrincnt++] = ZDLE;
break;
case ZCRCG:
case ZCRCE:
case ZCRCW:
case ZCRCQ:
rcrc = crc32 ? 5 : 3; /* either 3 or 5 bytes */
rtrn = k;
hdrbuf[hdrincnt++] = k;
break;
default:
hdrbuf[hdrincnt++] = k ^ 0x40;
break;
}
zdle_hit = 0;
if (rcrc)
{
if (--rcrc == 0)
{
return rtrn;
}
}
}
else if (k == ZDLE) /* zdle_hit == 0, and k==ZDLE */
{
zdle_hit = 1;
}
else /* zdle_hit==0, and k!=zdle */
{
hdrbuf[hdrincnt++] = k;
if (rcrc) /* if waiting for crc to complete */
{
rcrc--;
if (rcrc == 0)
{
return rtrn;
}
}
} /* end else */
} /* end while holdcnt != holdidx */
} /* end for (;;) */
}
check_crc(buf, cnt)
char *buf;
int cnt;
{
unsigned long uc;
unsigned c;
char *cp;
char *cp2;
if (crc32)
{
cp = buf + cnt;
cp2 = (char *) &uc;
cp2[0] = cp[0];
cp2[1] = cp[1];
cp2[2] = cp[2];
cp2[3] = cp[3];
if (uc != calccrc32(buf, cnt))
return 1;
else
return 0;
}
else
{
cp = buf + cnt;
cp2 = (char *) &c;
cp2[1] = cp[0];
cp2[0] = cp[1];
if (c != calccrc(buf, cnt))
{
return 1;
}
else
{
return 0;
}
}
}